const COS = require('cos-wx-sdk-v5');
import {
	v4 as uuidv4
} from 'uuid';
import StorageCache from '@/common/mediacache/index.js';
import fileObject from '@/common/upload/fileObject.js';
import { Sema } from 'async-sema';
const CryptoJS = require('crypto-js');  //引入crypto-js
class COSUploader {
	constructor() {
		this.tempKeys = {}; // 使用对象存储不同的 type 和 allow 组合的临时密钥
		this.types = {
			chat: 0,
			avatar: 1,
			stars: 2
		};
		this.allows = {
				upload: 0,
				see: 1,
			},
			this.uploadSema = new Sema(3); // 最大上传并发请求数为 3
		this.seeSema = new Sema(3); // 最大查看并发请求数为 3
	}

	async init(type = 'avatar', allow = 'upload') {
		// 检查是否已经有对应的临时密钥，或者过期了
		if (this.isKeyExpired(type, allow)) {
			try {
				const response = await uni.$api.unload.getUploadTmpKey({
					type: this.types[type],
					allow: this.allows[allow]
				})
				
				if (!this.tempKeys[type]) {
					this.tempKeys[type] = {};
				}
				// cryptojs
				let vkey = CryptoJS.enc.Utf8.parse('9k6j1rkn62q40fqu'); //传入的秘钥
				let viv = CryptoJS.enc.Utf8.parse('qh6jp5p0raye05be'); //传入的秘钥偏移量
				let decrypt = CryptoJS.AES.decrypt(response.data.value, vkey, { iv: viv, padding: CryptoJS.pad.Pkcs7 });
				let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
				let mydata = JSON.parse(decryptedStr.toString())
				this.tempKeys[type][allow] = mydata;
				// 实例化 COS 对象
				let domain = this.tempKeys[type][allow].domain? this.tempKeys[type][allow].domain : undefined
				this.tempKeys[type][allow].cos = new COS({
					SimpleUploadMethod: 'postObject',
					Domain: domain,
					getAuthorization: (options, callback) => {
						console.log(options);
						if (this.tempKeys[type][allow]) {
							callback({
								TmpSecretId: this.tempKeys[type][allow].tmpSecretId,
								TmpSecretKey: this.tempKeys[type][allow].tmpSecretKey,
								SecurityToken: this.tempKeys[type][allow].sessionToken,
								StartTime: this.tempKeys[type][allow].startTime,
								ExpiredTime: this.tempKeys[type][allow].expiredTime
							});
						}
					}
				});

			} catch (error) {
				console.error(`Failed to get temporary key for type=${type}, allow=${allow}:`, error);
				throw error;
			}
		}
	}
	//是否重新获取密钥
	isKeyExpired(type, allow) {
		const currentTime = Date.now() / 1000;
		return !this.tempKeys[type] || !this.tempKeys[type][allow] || currentTime >= this.tempKeys[type][allow]
			.expiredTime;
	}
	//上传文件filetype 为文件类型
	async uploadFile(tempFilePath, type = 'avatar', filetype, onProgressCallback) {
		await this.uploadSema.acquire();
		try {
			let allow = 'upload';
			let fileTypeObject = await fileObject.from_file(tempFilePath, type, filetype);
			let yudata = fileTypeObject.toRequest();
			// try {
			// 	let checkIsRes = await uni.$api.unload.checkIsExist({
			// 		upload_hash: yudata.file_hash,
			// 		upload_type: type
			// 	});
			// 	if (checkIsRes && checkIsRes.code == 200) {
			// 		onProgressCallback && onProgressCallback({
			// 			percent:1
			// 		});
			// 		StorageCache.setCachedUrl(`${filetype}_${type}_cache_list`, checkIsRes.data.url, tempFilePath);
			// 		return {
			// 			url: checkIsRes.data.url
			// 		};
			// 	}
			// } catch (e) {
			// 	console.error('检查失败---', e);
			// }
			await this.init(type, allow);
			if (!this.tempKeys[type] || !this.tempKeys[type][allow] || !this.tempKeys[type][allow].cos) {
				console.error('COS instance not initialized.');
				throw new Error('COS instance not initialized.');
			}
			let wy_id = uuidv4();
			let suffixName = tempFilePath.split('.').pop();
			let uploadKey = wy_id + '.' + suffixName;

			return new Promise((resolve, reject) => {
				this.tempKeys[type][allow].cos.postObject({
					Bucket: this.tempKeys[type][allow].bucket,
					Region: this.tempKeys[type][allow].region,
					Key: uploadKey,
					FilePath: tempFilePath,
					onProgress: function(info) {
						onProgressCallback && onProgressCallback(info);
					}
				}, async (err, data) => {
					if (err) {
						console.error('Upload error:', err);
						reject(err);
					} else {
						try{
							const savePath = await this.uniSaveFileAsync(tempFilePath);  // 保存文件并等待完成
							console.log(savePath);
							StorageCache.setCachedUrl(`${filetype}_${type}_cache_list`, uploadKey,savePath);
						}catch(e){}
						resolve({
							url: uploadKey
						});
						// try {
						// 	let resSave = await uni.$api.unload.saveUploadInfo({
						// 		...yudata,
						// 		url: uploadKey
						// 	});
						// 	if (resSave) {
						// 		resolve({
						// 			url: uploadKey
						// 		});
						// 	} else {
						// 		console.error('Server logging failure');
						// 		reject(new Error('Server logging failure'));
						// 	}
						// } catch (e) {
						// 	console.error('Upload error:', e);
						// 	reject(e);
						// }
					}
				});
			});
		} catch (error) {
			console.error('Upload failed:', error);
			throw error;
		} finally {
			this.uploadSema.release();
		}
	}
	// 将 uni.saveFile 包装为一个 Promise
	uniSaveFileAsync(tempFilePath) {
	  return new Promise((resolve, reject) => {
	    uni.saveFile({
	      tempFilePath: tempFilePath,
	      success: function (res) {
	        resolve(res.savedFilePath);
	      },
	      fail: function (err) {
	        reject(err);
	      }
	    });
	  });
	}
	//查看文件filetype 为文件类型
	async seeFile(fileKey, type = 'chat') {
		await this.seeSema.acquire();
		try {
			let allow = 'see';
			await this.init(type, allow);
			if (!this.tempKeys[type] || !this.tempKeys[type][allow] || !this.tempKeys[type][allow].cos) {
				console.error('COS instance not initialized.');
				throw new Error('COS instance not initialized.');
			}
			return new Promise((resolve, reject) => {
				this.tempKeys[type][allow].cos.getObjectUrl({
					Bucket: this.tempKeys[type][allow].bucket,
					Region: this.tempKeys[type][allow].region,
					Key: fileKey,
				}, function(err, data) {
					if (err) {
						console.error('Upload error:', err);
						reject(err);
					} else {
						resolve(data);
					}
				});
			});
		} catch (error) {
			console.error('see failed:', error);
			throw error;
		} finally {
			this.seeSema.release();
		}
	}
}

// 单例模式：保证只有一个实例存在
const singletonUploader = new COSUploader();

module.exports = singletonUploader;